package com.hksj.common.config.aop;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReflectUtil;
import com.hksj.common.config.annotation.RepeatableLimit;
import com.hksj.common.config.cache.RedisCache;
import com.hksj.common.core.model.Rest;
import com.hksj.common.core.util.IpUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Component
@Aspect
@Order(-100)
public class RepeatableLimitAspect {
    @Autowired
    private RedisCache<Long> redisCache;

    @Around("@annotation(repeatableLimit)")
    public Object limit(ProceedingJoinPoint joinPoint, RepeatableLimit repeatableLimit){
        Object res = null;
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String requestTimeStr = request.getHeader("request-time");
        //没有请求头就不拦截
        if (!ObjectUtils.isEmpty(requestTimeStr)){
            String identification = "";
            //有用户id用用户id
            Long currentUserId = getCurrentUserId();
            if (!ObjectUtils.isEmpty(currentUserId)){
                identification = currentUserId.toString();
            }else{
                //没有用户id 用 ip
                String ipAddr = IpUtils.getIpAddr(request);
                if (StringUtils.hasText(ipAddr)){
                    identification = ipAddr;
                }
            }
            if (!ObjectUtils.isEmpty(identification)){
                Long requestTime = Long.parseLong(requestTimeStr);
                String className = joinPoint.getTarget().getClass().getSimpleName();
                String methodName = joinPoint.getSignature().getName();
                String key = getKey(className, methodName, identification);
                Long lastTime = redisCache.getCacheObject(key);
                if (ObjectUtils.isEmpty(lastTime)){
                    redisCache.setCacheObject(key,requestTime,repeatableLimit.interval(), TimeUnit.SECONDS);
                }else {
                    long offset = DateUtil.between(new Date(lastTime), new Date(requestTime), DateUnit.SECOND);
                    if (offset <= repeatableLimit.interval()){
                        return Rest.fail("操作频繁，请稍后在试");
                    }
                }
            }
        }
        //执行方法
        try {
            res = joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e.getMessage());
        }

        return res;
    }

    private Long getCurrentUserId(){
        try{
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            Long userId = (Long)ReflectUtil.getFieldValue(ReflectUtil.getFieldValue(principal, "user"), "id");
            return userId;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    private String getKey(String className,String methodName,String identification){
        return new StringBuffer()
                .append(className)
                .append(":")
                .append(methodName)
                .append(":")
                .append(identification)
                .toString();
    }
}
